package com.ht.web_vr_home_tour_backend.service;

import cn.hutool.core.util.NumberUtil;
import cn.hutool.core.util.RandomUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ht.web_vr_home_tour_backend.config.data.RedisConstants;
import com.ht.web_vr_home_tour_backend.dao.UserInfoDao;
import com.ht.web_vr_home_tour_backend.obj.dto.UserInfoDto;
import com.ht.web_vr_home_tour_backend.obj.pojo.UserInfo;
import com.ht.web_vr_home_tour_backend.utils.CacheClient;
import com.ht.web_vr_home_tour_backend.utils.RedisIdWorker;
import com.ht.web_vr_home_tour_backend.utils.TokenUtil;
import com.ht.web_vr_home_tour_backend.utils.UserPwdUtil;
import com.ht.web_vr_home_tour_backend.utils.exceptions.MessageException;
import com.ht.web_vr_home_tour_backend.utils.exceptions.ServiceDataNullException;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.annotation.Validated;

import java.util.stream.Collectors;

@Service
public class UserInfoService extends ServiceImpl<UserInfoDao, UserInfo> {
    private final CacheClient cacheClient;

    private final RedisIdWorker redisIdWorker;

    @Lazy
    @Autowired
    private UserInfoService thisUserInfoService;

    public UserInfoService(CacheClient cacheClient, RedisIdWorker redisIdWorker) {
        this.cacheClient = cacheClient;
        this.redisIdWorker = redisIdWorker;
    }

    /**
     * 用户登录
     *
     * @param username 用户名
     * @param password 用户密码明文
     * @return 登录token，登录失败返回null
     */
    public String login(String username, String password) {
        if (StrUtil.isBlank(username) || StrUtil.isBlank(password)) {
            return null;
        }

        // 通过缓存读取用户数据
        UserInfo userFromDb = getUserByUsername(username);

        if (userFromDb == null) {
            return null;
        }
        boolean matches = UserPwdUtil.matches(userFromDb.getPassword(), password);
        if (matches) {
            return TokenUtil.createToken(new UserInfoDto(userFromDb));
        }
        return null;
    }

    /**
     * 根据用户名获取用户
     *
     * @param username 用户名
     * @return 用户数据
     */
    public UserInfo getUserByUsername(String username) {
        return cacheClient.queryWithMutex(UserInfo.class,
                RedisConstants.tb_UserInfo_keyPrefix,
                username,
                (key) -> this.getOne(this.lambdaQuery()
                        .eq(UserInfo::getUsername, key)
                        .last("limit 1")
                        .getWrapper()),
                RedisConstants.tb_Cache_Base_TTL);
    }

    /**
     * 根据id获取用户
     *
     * @param id 用户id
     * @return 用户
     */
    public UserInfo getUserById(String id) {
        if (StrUtil.isNotBlank(id) && NumberUtil.isLong(id)) {
            return cacheClient.queryWithMutex(UserInfo.class,
                    RedisConstants.tb_UserInfo_keyPrefix,
                    id,
                    (key) -> this.getOne(this.lambdaQuery()
                            .eq(UserInfo::getId, id)
                            .last("limit 1")
                            .getWrapper()),
                    RedisConstants.tb_Cache_Base_TTL);
        }
        return null;
    }


    /**
     * 创建用户
     *
     * @param newUserInfo 新用户的数据
     */
    public long createUser(@Validated UserInfo newUserInfo) {
        if (newUserInfo == null ||
                newUserInfo.getUsername() == null ||
                newUserInfo.getPassword() == null
        ) {
            throw new ServiceDataNullException();
        }
        long id = redisIdWorker.nextId(RedisConstants.icr_UserInfo_keyPrefix);
        if (newUserInfo.getId() == null) {
            newUserInfo.setId(id);
        }
        if (newUserInfo.getAvatar() == null) {
            newUserInfo.setAvatar("basic/avatar");
        }
        if (newUserInfo.getNickName() == null) {
            newUserInfo.setNickName(RandomUtil.randomString("abcdefghijklmnopqrstuvwxyz1234567890", 10));
        }
        String pwd = newUserInfo.getPassword();
        newUserInfo.setPassword(UserPwdUtil.encode(pwd));
        UserInfo one = this.getOne(this.lambdaQuery().eq(UserInfo::getUsername, newUserInfo.getUsername()).last("limit 1").getWrapper());
        if (one != null) {
            throw new MessageException("用户已存在，请直接登录或更换用户信息");
        }
        this.save(newUserInfo);
        return id;
    }

    /**
     * 分页查找用户
     *
     * @param current 当前页
     * @param size    分页大小
     * @return 查询数据
     */
    public IPage<UserInfoDto> pageUser(long current, long size) {
        IPage<UserInfo> userInfoPage = new Page<>(current, size);
        this.page(userInfoPage);
        IPage<UserInfoDto> res = new Page<>();
        BeanUtils.copyProperties(userInfoPage, res);
        res.setRecords(userInfoPage.getRecords().stream().map(UserInfoDto::new).collect(Collectors.toList()));
        return res;
    }

    /**
     * 更新用户
     *
     * @param userInfo 新用户的数据
     */
    @Transactional
    public UserInfo updateUser(UserInfo userInfo) {
        boolean exists = this.exists(this.lambdaQuery().eq(UserInfo::getId, userInfo.getId()).getWrapper());
        if (!exists) {
            throw new MessageException("用户不存在");
        }
        this.updateById(userInfo);
        cacheClient.dropCache(RedisConstants.tb_UserInfo_keyPrefix, String.valueOf(userInfo.getId()));
        return this.getById(userInfo.getId()); // 这个方法不能走缓存，缓存无法被事务覆盖到，返回的和传入的参数可能不一致
    }
}
